package com.elitel.common.businessJdbc;

import com.elitel.common.businessJdbc.mysql.MysqlScriptPreparedStatement;
import com.elitel.common.businessJdbc.oracle.OracleScriptPreparedStatement;
import com.elitel.common.businessJdbc.postgre.PostgreSQLScriptPreparedStatement;
import com.elitel.common.businessJdbc.sqlserver.SqlServerScriptPreparedStatement;
import com.elitel.common.utils.XCommonUtils;
import com.elitel.frame.main.entity.access.FilterSqlHandlerDTO;
import com.elitel.frame.main.entity.constant.DictionaryConstant;
import lombok.Data;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

// here is provider data structure for script
@Data
public abstract class BusinessScriptPreparedStatement extends AbstractBusinessPreparedStatement{

    // here is only existed replace sql with {{{content}}}
    // here is can replace by using question
    // by using content to find corresponding field type
    // so I have existed origin sql ? with openToken and closeToken
    // maybe it's not necessary I have replace by using question , record index and type by content field
    private String sqlWithPlaceHolder;
    // here content to find type of java
    private Map<String, String> fieldTypeMap;
    // here content and value for precompile placeholder here is LinkedHashMap record order
    private Map<String, Object> placeHolderOrderColumnObject;
    private Map<String, String> passCondition;

    // here is order section
    private String orderSection;

    // pageable
    private boolean isPageable;
    protected int pageNumber = 1;
    protected int pageSize = 10;
    /**过滤数据SQL处理对象*/
    protected FilterSqlHandlerDTO filterSqlHandlerDTO;

    public String getPrecompileCountSql(){
        StringBuilder sb = new StringBuilder();
        sb.append(" select count(*) from ( ")
            .append(sqlWithPlaceHolder)
            .append(" ) a ");
        return sb.toString();
    }

    public static Builder builder(){
        return new Builder(DictionaryConstant.DatabaseType_MYSQL);
    }

    public static Builder builder(String databaseType){
        return new Builder(databaseType);
    }

    public static class Builder{
       private static final String openToken = XCommonUtils.OpenToken;
       private static final String closeToken = XCommonUtils.CloseToken;

        private String serviceGuid;
        private String databaseType;

        // here is contain origin sql with custom token
        // order to replace the customToken , recorder content ,1. find content type 2. match value by content string match
        private String originSqlWithCustomToken;
        private StringBuilder concatSqlWithPlaceHolder = new StringBuilder();

        private Map<String, Object> placeHolderOrderColumnObject = new LinkedHashMap<>();

        private Map<String, Object> passCondition;
        private Map<String, String> fieldTypeMap;
        private boolean isPageable;
        private int pageNumber;
        private int pageSize;
        private FilterSqlHandlerDTO filterSqlHandlerDTO;

        public Builder(String databaseType){
            this.databaseType = databaseType;
        }

        public Builder serviceGuid(String serviceGuid){
            this.serviceGuid = serviceGuid;
            return this;
        }

        public Builder originSqlWithCustomToken(String originSqlWithCustomToken){
            this.originSqlWithCustomToken = originSqlWithCustomToken;
            return this;
        }

        public Builder fieldTypeMap(Map<String,String> fieldTypeMap){
            this.fieldTypeMap = fieldTypeMap;
            return this;
        }
        public Builder filterSqlHandler(FilterSqlHandlerDTO filterSqlHandlerDTO){
            this.filterSqlHandlerDTO = filterSqlHandlerDTO;
            return this;
        }

        public Builder passCondition(Map<String, Object> passCondition){
            if(passCondition == null)
                this.passCondition = new HashMap<>();
            else
                this.passCondition = passCondition;

            return this;
        }

        public Builder isPageable(boolean isPageable){
            this.isPageable = isPageable;
            return this;
        }

        public Builder pageNumber(String pageNo){
            int pageNumber;
            try{
                pageNumber = Integer.parseInt(pageNo);

            }catch(Exception e){
                pageNumber = 1;
            }
            this.pageNumber = pageNumber;
            return this;
        }

        public Builder pageSize(String strPageSize){
            int pageSize;
            try{
                pageSize = Integer.parseInt(strPageSize);
            }catch(Exception e){
                pageSize = 10;
            }
            this.pageSize = pageSize;
            return this;
        }

        private BusinessScriptPreparedStatement createBusinessPreparedStatementByDatabaseType() {
            BusinessScriptPreparedStatement bps;
            switch(databaseType){
                case DictionaryConstant.DatabaseType_MYSQL:
                    bps = new MysqlScriptPreparedStatement();
                    break;
                case DictionaryConstant.DatabaseType_POSTGRESQL:
                    bps = new PostgreSQLScriptPreparedStatement();
                    break;
                case DictionaryConstant.DatabaseType_ORACLE:
                    bps = new OracleScriptPreparedStatement();
                    break;
                case DictionaryConstant.DatabaseType_SQLSERVER:
                    bps = new SqlServerScriptPreparedStatement();
                    break;
                default:
                    bps = new DefaultScriptPreparedStatement();
            }
            return bps;
        }

        public BusinessScriptPreparedStatement build(){
            BusinessScriptPreparedStatement bps = createBusinessPreparedStatementByDatabaseType();

            bps.setServiceGuid(serviceGuid);
            bps.setDatabaseType(databaseType);
            bps.setFieldTypeMap(fieldTypeMap);
            bps.setPageable(isPageable);
            if(bps.isPageable()){
                bps.setPageNumber(pageNumber);
                bps.setPageSize(pageSize);
            }

            replaceCustomToken(originSqlWithCustomToken);
            // here is precompile sql
            bps.setSqlWithPlaceHolder(concatSqlWithPlaceHolder.toString());
            // here is placeHolderOrderColumnObject
            bps.setPlaceHolderOrderColumnObject(placeHolderOrderColumnObject);
            bps.setFilterSqlHandlerDTO(filterSqlHandlerDTO);
            return bps;
        }

        public void replaceCustomToken(String sqlText){
 //           info("complete sqlText: " + sqlText);
            int openTokenIndex = sqlText.indexOf(openToken);
            int closeTokenIndex = sqlText.indexOf(closeToken);

            // info("openTokenIndex: " + openTokenIndex);
            // info("closeTokenIndex: " + closeTokenIndex);

            String readSql;
            if(openTokenIndex != -1){
                readSql = sqlText.substring(0, openTokenIndex);
            }else{
                readSql = sqlText;
            }

            concatSqlWithPlaceHolder.append(readSql).append(" ");

            String content = "";
            String subSql = "";

            if (openTokenIndex != -1 && closeTokenIndex != -1) {
                content = sqlText.substring(openTokenIndex + 3, closeTokenIndex).trim();
                subSql = sqlText.substring(closeTokenIndex + 3);
                concatSqlWithPlaceHolder.append(" ? ");
                // here is record
                Object value = passCondition.get(content);
                //placeHolderOrderColumnObject.put(content, value);
                String key = String.valueOf(placeHolderOrderColumnObject.size() + 1);
                Map<String, Object> queryMap = new HashMap();
                queryMap.put("key", content);
                queryMap.put("val", value);
                placeHolderOrderColumnObject.put(key, queryMap);
            }

            // info("readSql: " + readSql);
            // info("content: " + content);
            // info("subSql: " + subSql);

            if(XCommonUtils.isEmpty(subSql))
                return;

            replaceCustomToken(subSql);
        }


        public void info(String content){
            System.out.println(content);
        }

    }

    // public static void main(String[] args){
    //     String sql = " select * from irrp_m_autoIrrUnit where irrUnitId = {{{irrUnitId}}} and 1 = 1 and irrUnitName = {{{irrUnitName}}}";
    //     builder().replaceCustomToken(sql);
    // }


}
